using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using CrystalCore.Libs;
using CrystalCore.AI;
using Microsoft.Xna.Framework;
using CrystalCore.Mapping;
using Jitter.Dynamics;

namespace CrystalCore.Actors
{
    public abstract class Actorbase : IPathableEntity, ISelectable3D
    {
        protected partial class ActorPrim : PhysicsPrim
        {
            public ActorPrim(Vector3 pos)
                : base(pos)
            {
                this.IsStatic = true;
                this.AffectedByGravity = false;
                this.Rescale(Vector3.One);
            }

            public Matrix World
            {
                get
                {
                    return
                        Matrix.CreateScale(this.Scale)
                        *
                        Matrix.CreateRotationX(Rotation.X) *
                        Matrix.CreateRotationY(Rotation.Y) *
                        Matrix.CreateRotationZ(Rotation.Z)
                        *
                        Matrix.CreateTranslation(Converter.ConvertVect(this.Position));
                }
            }
        }

        //Fields        
        private float _WalkSpeed { get; set; }
        protected ActorPrim _ActorPrimitive;

        public Vector3 Position
        {
            get { return Converter.ConvertVect(_ActorPrimitive.Position); }
            set { _ActorPrimitive.Reposition(value); }
        }
        public WaypointPath Path;
        public Vector3 MoveDirection;
                  
        //cTor
        public Actorbase(MazePosition position)
        {
            _WalkSpeed = .11f;
            this._ActorPrimitive = new ActorPrim(new Vector3(
                (position.X * Globals.CellSize.X) + (Globals.CellSize.X / 2),
                .5f,
                (position.Z * Globals.CellSize.Z) + (Globals.CellSize.Z / 2)));

            this.Position = position.CenterCell + new Vector3(0, 1, 0);
            this._ActorPrimitive.Rescale(Globals.ActorSize);
            this.Path = new WaypointPath(this);
            this.Path.RepeatMode = EntityPathRepeatMode.IterateOnce;
            this.Path.MoveDirectionChanged += (s, e) => { MoveDirection = e.NewDirection; };
        }

        //Methods
        public void DrawActor(GameTime time)
        {
            if (ObjectHolder.GameWorld == null)
                throw new CrystalCoreFrameworkError(CrystalCoreErrors.NoGameWorld);

            if (ObjectHolder.GameWorld == null)
                throw new CrystalCoreFrameworkError(CrystalCoreErrors.NoGameCamera);

            RenderActor(time);

            if (Globals.DrawPrimitivesInDebugMode)
            {
                if (ObjectHolder.GlobalDebugRenderer == null)
                    throw new CrystalCoreFrameworkError(CrystalCoreErrors.NoGlobalDebugDrawer);


                ObjectHolder.GlobalDebugRenderer.DrawAabb(_ActorPrimitive.BoundingBox.Min, _ActorPrimitive.BoundingBox.Max, Globals.DebugColour);
            }
        }
        public virtual void UpdateActor(GameTime time)
        {
            if (Path != null)
                Path.UpdatePath(time);
        }

        protected abstract void RenderActor(GameTime time);

        public void SetAndStartpath(IEnumerable<Waypoint> nodes)
        {
            if (IsControlled)
                return;

            this.Path.Clear();
            this.Path.AddRange(nodes.Reverse());
            this.Path.Start();
        }
        public void SetAndStartpath(params Waypoint[] nodes)
        {
            SetAndStartpath(nodes.AsEnumerable());
        }

        public void MoveTo(MazePosition mazePosition)
        {
            IEnumerable<MazePosition> path = AStarSolver.FindPath(ObjectHolder.LevelMap,
                MazePosition.FromVector3(this.Position, Globals.CellSize),
                mazePosition);

            if (path != null)
            {
                this.SetAndStartpath(path.Select(p => { return new Waypoint(p); }));
                return;
            }
        }

        #region Pathable Entity
        public Vector3 EntityPosition
        {
            get { return Position; }
            set { Position = value; }
        }
        public float ActorSpeed
        {
            get {return _WalkSpeed; }

        }
        public bool IsControlled
        {
            get;
            set;
        }
        public float Rotation
        {
            get { return _ActorPrimitive.Rotation.Y; }
            set { _ActorPrimitive.SetRotation(0f, value, 0f); }
        }
        #endregion

        #region ISelectable
        public string ID
        {
            get;
            set;
        }
        public RigidBody Body
        {
            get { return _ActorPrimitive; }
        }
        public MazePosition SelectablePosition
        {
            get { return MazePosition.FromVector3(Position, Globals.CellSize); }
        }
        public SelectableState SelectionState
        {
            get;
            set;
        }
        #endregion
    }
}
